package com.ti.demo.configuration;

import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.client.observation.ChatClientObservationConvention;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

/**
 * @description: com.ti.demo.configuration
 * @Author Triagen
 * @Date 2025/7/18 11:12
 */
@Configuration
public class ChatClientConfiguration {

    /**
     * a manual ChatClient example,for better understanding of api, model and chatClient
     * generally speaking, api includes the connection info, model includes the model choice, and chatClient is the assembly of both
     *
     * @param deepSeekChatModel
     * @return
     */
    @Bean("deepSeekChatClient")
    public ChatClient chatClient(DeepSeekChatModel deepSeekChatModel,
                                 ChatMemory chatMemory,
                                 ObjectProvider<ObservationRegistry> observationRegistry,
                                 ObjectProvider<ChatClientObservationConvention> observationConvention,
                                 List<ToolCallbackProvider> tcbProviders) {
        return ChatClient.builder(deepSeekChatModel,
                        observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP),   // 参考 ChatClientAutoConfiguration.chatClientBuilder，需要注入 ObservationRegistry
                        observationConvention.getIfUnique(() -> null))
                .defaultSystem("""
                                你是一个基金投资文档检索小助手，当用户问你提问时，你应该调用工具获取相关信息.若工具调用失败，你需要认真分析失败原因，给出进一步的工具调用方案。
                                譬如：若工具调用出现路径无法访问，你应该调用工具确认当前路径，而不是直接返回路径无法访问
                                ### 文档名格式：基金名(基金代码)，
                                ### 禁止回复未经检索的内容
                                """
                        )
                .defaultAdvisors(
                        SimpleLoggerAdvisor.builder().build(),
                        MessageChatMemoryAdvisor.builder(chatMemory).build())  // 上下文配置
                .defaultToolCallbacks(tcbProviders.toArray(new ToolCallbackProvider[0]))   // 工具配置
                .build();
    }

}
